package cz.muni.fi.pa165.library.backend;

import cz.muni.fi.pa165.library.api.Available;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.springframework.stereotype.Repository;

/**
 *
 * @author Marián Labuda
 * @version 1.4
 */
@Repository
public class ReservationDAOImpl implements ReservationDAO {

    @PersistenceContext(name = "LibraryPU")
    private EntityManager entityManager;

    @PersistenceContext
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public Reservation insertReservation(Reservation reservation) {
        if (reservation == null) {
            throw new IllegalArgumentException("Reservation cannot be null") {
            };
        }
        if (reservation.getReservationID() != null) {
            throw new IllegalArgumentException("ID of reservation is already set. ID must be generated automatically.\n") {
            };
        }
        if (!reservation.getBook().getAvailability().equals(Available.AVAILABLE)) {
            throw new IllegalArgumentException("Book must be available to be reserved") {
            };
        }

        Book book = entityManager.find(Book.class, reservation.getBook().getId());
        book.setAvailability(Available.RESERVED);
        entityManager.persist(book);

        entityManager.persist(reservation);
        return reservation;
    }

    public Reservation findReservationByBook(Book book) {
        if (book == null) {
            throw new IllegalArgumentException("Book cannot be null") {
            };
        }
        if (book.getId() == null) {
            throw new IllegalArgumentException("Id of book cannot be null") {
            };
        }
        Query query = entityManager.createQuery("SELECT r FROM Reservation r WHERE r.book = :book");
        query.setParameter("book", book);
        Reservation reservation = null;
        try {
            reservation = (Reservation) query.getSingleResult();
        } catch (NoResultException ex) {
        } finally {
            return reservation;
        }
    }

    public List<Reservation> findReservationsByReader(Reader reader) {
        if (reader == null) {
            throw new IllegalArgumentException("Reader cannot be null") {
            };
        }
        if (reader.getId() == null) {
            throw new IllegalArgumentException("Id of reader cannot be null") {
            };
        }
        Query query = entityManager.createQuery("SELECT r FROM Reservation r WHERE r.reader = :reader");
        query.setParameter("reader", reader);
        List<Reservation> reservationList = null;
        try {
            reservationList = query.getResultList();
        } finally {
            return reservationList;
        }

    }

    public List<Reservation> findAllReservations() {
        List<Reservation> reservationList;
        reservationList = entityManager.createQuery("SELECT r FROM Reservation r", Reservation.class).getResultList();
        return reservationList;
    }

    public boolean deleteReservation(Reservation reservation) {
        if (reservation == null) {
            throw new IllegalArgumentException("Cannot delete imaginary reservation") {
            };
        }
        if (reservation.getReservationID() == null) {
            throw new IllegalArgumentException("ID of reservation cannot be null.") {
            };
        }
        if (!reservation.getBook().getAvailability().equals(Available.RESERVED)) {
            throw new IllegalStateException("There is reservation on book which is not reserved.");
        }
        Reservation reservationEntity = entityManager.find(Reservation.class, reservation.getReservationID());
        if (reservationEntity == null) {
            throw new IllegalArgumentException("Cannot delete non-existing reservation") {
            };
        }

        Book book = entityManager.find(Book.class, reservation.getBook().getId());
        book.setAvailability(Available.AVAILABLE);
        entityManager.persist(book);

        entityManager.remove(reservationEntity);

        return true;
    }

    public Reservation findReservationByID(Long id) {
        if (id == null) {
            throw new IllegalArgumentException("Id cannot be null") {
            };
        }
        if (id.longValue() <= 0) {
            throw new IllegalArgumentException("Id must be greater than 0") {
            };
        }
        Query query = entityManager.createQuery("SELECT r FROM Reservation r WHERE r.reservationID = :id");
        query.setParameter("id", id);
        Reservation reservation = null;
        try {
            reservation = (Reservation) query.getSingleResult();
        } catch (NoResultException ex) {
        } finally {
            return reservation;
        }
    }
}
